<template>
  <view class="container">
    <!-- 顶部自定义导航，抽离成公共组件，所有页面复用 -->
    <CustomNavbar
      title="海马体·美力全开"
    />

    <!-- 全局加载遮罩（在数据载入完成前显示） -->
    <view v-if="!isLoaded" class="loading-overlay">
      <view class="loading-box">
        <view v-if="longLoading" class="loading-note">当前参赛人员较多，请耐心等待</view>
        <view class="spinner">
          <view class="dot" v-for="n in 3" :key="n"></view>
        </view>
        <view class="loading-text">数据加载中...</view>
      </view>
    </view>

    <!-- 非参赛人员开场弹窗（仅首次显示） -->
    <view v-if="showOpeningPopup && !isShowLookBox && isLoaded" class="opening-popup-overlay">
      <view class="opening-popup" @tap.stop>
        <image class="opening-image" src="/static/open.png" mode="aspectFill" />
        <view class="opening-close" @tap.stop="closeOpeningPopup">我知道了</view>
      </view>
    </view>
    <!-- 参赛人员并且没有上界称号的开场弹窗（仅首次显示） -->
    <view v-if="showOpeningPopup && isShowLookBox && !isLastYearChampion && isLoaded" class="opening-popup-overlay">
      <view class="opening-popup" @tap.stop>
        <image class="opening-image" src="/static/open.png" mode="aspectFill" />
        <view class="opening-close" @tap.stop="closeOpeningPopup">我知道了</view>
      </view>
    </view>
    <!-- 参数人员并且有上界称号的展示（仅首次显示） -->
    <view v-if="showOpeningPopup && isLastYearChampion && isLoaded" class="opening-popup-overlay">
      <view class="opening-popup" @tap.stop>
        <view class="tips">欢迎上届HIMO{{userInfo.title}}，荣誉回归，<view>期待你的精彩表现！</view></view>
        <view class="opening-text">每一年都奔跑在热爱里</view>
        <view class="opening-close" @tap.stop="closeOpeningPopup">我知道了</view>
      </view>
    </view>
    <!-- 使用公共内容容器，自动应用导航高度的 padding -->
    <view class="title-box">
      <view>海马体全国</view>
      <view>技能审美活动</view>
    </view>
    <!-- 主体内容：页面加载完成（isLoaded）后再展示，避免真机首次渲染显示占位内容 -->
    <view v-if="isLoaded">
    
    <!-- <view class="tips" v-if="isOneInPage">每一年都奔跑在热爱里</view> -->
    <PublicContentLayout v-if="isShowLookBox&&isLoaded">
      <!-- 页面内容 -->
      <view class="manifesto-container" v-if="manifesto">
        <view class="manifesto-content">{{ manifesto }}</view>
      </view>
      <view class="content-box" v-else>
        <view class="input-box">
          <input type="text" placeholder="请输入您的获奖宣言或选择已有宣言~" maxlength="25" class="input-phone" v-model="manifestoInput" />
        </view>
        <view class="manifesto-box">
          <view class="manifesto-title">选择已有宣言</view>
          <view class="manifesto-lines">
            <view class="marquee-line line1">
              <view class="marquee-track" :style="{ animationDuration: '72s' }">
                <view class="manifesto-item" v-for="(item, index) in manifestoList" :key="'l1-'+index" @tap="selectManifesto(item)">{{ item.name }}</view>
                <view class="manifesto-item" v-for="(item, index) in manifestoList" :key="'l1-dup-'+index" @tap="selectManifesto(item)">{{ item.name }}</view>
              </view>
            </view>
            <view class="marquee-line line2">
              <view class="marquee-track" :style="{ animationDuration: '86s' }">
                <view class="manifesto-item" v-for="(item, index) in manifestoList" :key="'l2-'+index" @tap="selectManifesto(item)">{{ item.name }}</view>
                <view class="manifesto-item" v-for="(item, index) in manifestoList" :key="'l2-dup-'+index" @tap="selectManifesto(item)">{{ item.name }}</view>
              </view>
            </view>
            <view class="marquee-line line3">
              <view class="marquee-track" :style="{ animationDuration: '106s' }">
                <view class="manifesto-item" v-for="(item, index) in manifestoList" :key="'l3-'+index" @tap="selectManifesto(item)">{{ item.name }}</view>
                <view class="manifesto-item" v-for="(item, index) in manifestoList" :key="'l3-dup-'+index" @tap="selectManifesto(item)">{{ item.name }}</view>
              </view>
            </view>
          </view>
        </view>
      </view>
    </PublicContentLayout>
    <PublicContentLayout v-if="isLoaded">
      <view class="bottom-box" v-if="isShowLookBox">
        <button class="look-box-btn" @tap="navigateToTopList('全国蓝标')">蓝标赛场</button>
        <button class="look-box-btn" @tap="navigateToTopList('全国大师')">大师赛场</button>
        <button class="look-box-btn" @tap="navigateToTopList('全国云端')">云端赛场</button>
      </view>
      <view v-else class="non-participant-area">
        <view class="grid-container">
          <button class="grid-btn" @tap="navigateToTopList('蓝标-服务管家赛场')">蓝标-服务管家赛场</button>
          <button class="grid-btn" @tap="navigateToTopList('大师-服务管家赛场')">大师-服务管家赛场</button>
          <button class="grid-btn" @tap="navigateToTopList('蓝标-造型顾问赛场')">蓝标-造型顾问赛场</button>
          <button class="grid-btn" @tap="navigateToTopList('大师-造型顾问赛场')">大师-造型顾问赛场</button>
          <button class="grid-btn" @tap="navigateToTopList('蓝标-摄影师赛场')">蓝标-摄影师赛场</button>
          <button class="grid-btn" @tap="navigateToTopList('大师-摄影师赛场')">大师-摄影师赛场</button>
          <button class="grid-btn" @tap="navigateToTopList('蓝标-看片师赛场')">蓝标-看片师赛场</button>
          <button class="grid-btn" @tap="navigateToTopList('大师-看片师赛场')">大师-看片师赛场</button>
          <button class="grid-btn full" @tap="navigateToTopList('云端-修图师赛场')">云端-修图师赛场</button>
        </view>
      </view>
    </PublicContentLayout>
    <view class="look-box" v-if="isShowLookBox&&isLoaded">
      <button class="look-box-btn" @tap="navigateToLookInfo">查看比赛信息</button>
    </view>
    <view v-if="isShowLookBox&&isLoaded" class="active-rules-btn" @tap="navigateToActiveRules">活动说明</view>
    </view>

  </view>
</template>

<script>
import CustomNavbar from '@/components/CustomNavbar.vue'
import PublicContentLayout from '@/components/PublicContentLayout.vue'
import { getDingDingUid, searchPersonalInfo, publishDeclaration } from '@/api/base'
import AllUserInfo from '../../static/AllUserInfo'

export default {
  components: { CustomNavbar, PublicContentLayout },
  data() {
    return {
      showOpeningPopup: false, // 是否显示开场弹窗（首次）
      isOneInPage: false, // 是否首次进入
      isLastYearChampion: false, // 参赛者是否上届有称号
      isShowLookBox: true, // 是否是参赛人员
      manifesto: '', // 用户已保存宣言
      userInfo: {}, // 用户信息
      manifestoInput: '',
      manifestoList: [
        { name: '每一年都奔跑在热爱里' },
        { name: '为世界呈现心动的美好' },
        { name: '为人们展现特质、表达情感' },
        { name: '生活需要仪式感' },
        { name: '专业可靠、懂我心意、温暖贴心' },
        { name: '记录美好回忆、展现真实自信之美、探索多元的自我' },
        { name: '用凝聚的场域，让用户被欢迎、被看见、被记住' },
        { name: '奔跑吧，我的热爱电量满格！' },
        { name: '靠谱在线，永不掉线！' },
        { name: '步履不停，热爱不灭！' },
        { name: '在场域里，找到共鸣的回响～' },
        { name: '懂你所想，胜我所长～' },
        { name: '我晒我的轨迹，亮出我的光芒四射！' },
        { name: '有专业、有审美、有温度，我拿捏了！' },
        { name: '我的主场，请多指教！' },
        { name: '仪式感，是给自己的掌声！' },
        { name: '你美力全开，我全力以赴！' },
        { name: '轨迹很酷，不服来追！' },
        { name: '场域BUFF，状态拉满！' },
        { name: '步履所至，皆是热爱～' }
      ],
      WholeParticipantInfoList: [],
      // 关闭动作为防止重复点击造成多次触发
      closingPopupInProgress: false,
      isLoaded: false, // 信息是否准备完成
      longLoading: false,
      longLoadingTimer: null,
    }
  },
  onLoad() {
    // 只有首次进入isOneInPage=true
    // start long-loading timer in case data load takes long
    try { this.startLongLoadingTimer && this.startLongLoadingTimer(); } catch (e) {}
    dd.getStorage({
      key: 'isOneInPage',
      success: (res) => {
        this.isOneInPage = res.data;
        // 如果存储里标记为首次访问（不存在或为false），本地也设置不再显示下次弹窗
        if (!this.isOneInPage) {
          this.showOpeningPopup = true;
          this.isOneInPage = true;
          dd.setStorage({ key: 'isOneInPage', data: true });
        }
      },
      fail: () => {
        // 没取到则说明是第一次访问，显示开场弹窗并写入 storage
        this.showOpeningPopup = true;
        this.isOneInPage = true;
        dd.setStorage({ key: 'isOneInPage', data: true });
      },
    });
    // this.getUserInfo();
  },
  onReady() {
    this.w =AllUserInfo
    // 修复Android渲染问题
    setTimeout(() => { dd.setNavigationBar({ title: '' }); }, 100);
    // 兼容性检测：仅在支持该 API 的环境中调用
    if (typeof dd !== 'undefined' && typeof dd.getMenuButtonBoundingClientRect === 'function') {
      const menu = dd.getMenuButtonBoundingClientRect();
      console.log(menu, "胶囊按钮位置");
    } else {
      console.log("dd.getMenuButtonBoundingClientRect 不可用，跳过胶囊按钮位置检测");
    }
    this.getUserInfo();
  },
  onShow() {
    // 页面可见时刷新宣言并校验参赛身份（如果已知用户工号）
    try {
      const wn = this.userInfo && (this.userInfo.workNumber || this.userInfo.staffId) ? Number(this.userInfo.workNumber || this.userInfo.staffId) : null;
      if (!wn) return;
      searchPersonalInfo(wn).then((resp) => {
        let body = resp;
        if (typeof body === 'string') {
          try { body = JSON.parse(body); } catch (e) { /* ignore */ }
        }

        let entry = null;
        if (Array.isArray(body)) {
          entry = body.find(it => String(it.workNumber) === String(wn));
        } else if (body && typeof body === 'object') {
          if (String(body.workNumber) === String(wn)) {
            entry = body;
          } else if (Array.isArray(body.msg)) {
            entry = body.msg.find(it => String(it.workNumber) === String(wn));
          } else if (Array.isArray(body.data)) {
            entry = body.data.find(it => String(it.workNumber) === String(wn));
          } else if (Array.isArray(body.result)) {
            entry = body.result.find(it => String(it.workNumber) === String(wn));
          } else if (body.msg && typeof body.msg === 'object' && String(body.msg.workNumber) === String(wn)) {
            entry = body.msg;
          } else if (body.data && typeof body.data === 'object' && String(body.data.workNumber) === String(wn)) {
            entry = body.data;
          } else if (body.result && typeof body.result === 'object' && String(body.result.workNumber) === String(wn)) {
            entry = body.result;
          }
        }

        if (entry) {
          if (typeof entry.declaration !== 'undefined' && String(entry.declaration).trim() !== '') {
            this.manifesto = String(entry.declaration).trim();
          }
          this.isShowLookBox = true;
        } else {
          this.isShowLookBox = false;
        }
      }).catch(() => {});
    } catch (e) {}
  },
  methods: {
    // Start a timer to show an extended-loading note after 3s
    startLongLoadingTimer() {
      try {
        this.longLoading = false;
        if (this.longLoadingTimer) clearTimeout(this.longLoadingTimer);
        this.longLoadingTimer = setTimeout(() => { this.longLoading = true; this.longLoadingTimer = null; }, 3000);
      } catch (e) { this.longLoading = false; this.longLoadingTimer = null; }
    },

    // Clear any running long-loading timer and reset flag
    clearLongLoadingTimer() {
      try {
        if (this.longLoadingTimer) { clearTimeout(this.longLoadingTimer); this.longLoadingTimer = null; }
      } catch (e) {}
      this.longLoading = false;
    },

    /**
     * 获取当前用户信息
     */
    getUserInfo() {
      dd.getAuthCode({
        corpId: 'dingd351390805a24dbb35c2f4657eb6378f',
        success: (res) => {
          const { authCode } = res;
          getDingDingUid(authCode).then(res => {
            if(res.success) {
              const dingdingUid = JSON.parse(res.msg)?.result?.userid;
              // const dingdingUid = '02644147-191954072'  // 蓝标
              // const dingdingUid = '0867224321-1100131837'  // 蓝标

              console.log(dingdingUid, "dingdingUid-------4-");
              // 根据dingdingUid查出用户信息（如果有的话）
              const userInfo = [...AllUserInfo].find(item => item && item.dingdingUid === dingdingUid);
              console.log(userInfo, "userInfo--------");

              // 如果未查到，说明不是参赛人员，isShowLookBox=false。并清理可能存在的 CurrentUserWorkNumber
              if(!userInfo) {
                this.isShowLookBox = false;
                dd.setStorage({ key: 'isShowLookBox', data: false });
                try {
                  if (typeof dd !== 'undefined' && typeof dd.removeStorage === 'function') {
                    dd.removeStorage({ key: 'CurrentUserWorkNumber' });
                  } else {
                    dd.setStorage({ key: 'CurrentUserWorkNumber', data: '' });
                  }
                } catch (e) {}
                this.isLoaded = true;
                this.clearLongLoadingTimer();
                return;
              }

              dd.setStorage({ key: 'isShowLookBox', data: true });
              this.userInfo = userInfo;
              // if(userInfo.title) this.isLastYearChampion = true;

              // Try to fetch existing declaration from backend (searchPersonalInfo returns declaration)
              try {
                const wn = userInfo && (userInfo.workNumber || userInfo.staffId) ? Number(userInfo.workNumber || userInfo.staffId) : null;
                if (wn) {
                  searchPersonalInfo(wn).then((resp) => {
                    if(resp.success) {
                      this.manifesto = resp.msg.declaration;
                      this.userInfo = resp.msg;
                       // 设置当前用户工号
                      dd.setStorage({ key: 'CurrentUserWorkNumber', data: wn });
                    }

                    this.isLoaded = true;
                    this.clearLongLoadingTimer();
                  }).catch(() => {
                    this.isLoaded = true;
                    this.clearLongLoadingTimer();
                    this.isShowLookBox = false;
                    try { dd.setStorage({ key: 'isShowLookBox', data: false }); } catch (e) {}
                  });
                } else {
                  // no work number available
                  this.isLoaded = true;
                  this.clearLongLoadingTimer();
                }
              } catch (e) {}
            } else {
              console.log("测试接口是否可用失败");
            }
          })
        },
        fail: () => {
          this.isLoaded = false;
          this.isShowLookBox = false;
          try {
            if (typeof dd !== 'undefined' && typeof dd.removeStorage === 'function') {
              dd.removeStorage({ key: 'CurrentUserWorkNumber' });
            } else {
              dd.setStorage({ key: 'CurrentUserWorkNumber', data: '' });
            }
          } catch (e) {}
        },
        complete: () => {},
      });
    },

    /**
     * 跳转至查看比赛信息页面
     */
    navigateToLookInfo() {
      const wn = this.userInfo && this.userInfo.workNumber ? this.userInfo.workNumber : null;
      const already = this.manifesto && String(this.manifesto).trim() !== '';
      const proceedNavigate = () => { dd.navigateTo({ url: `/pages/personal/index?workNumber=${wn}` }); };

      if (already || !wn) { proceedNavigate(); return; }

      // determine declaration to save: user input or random pick
      let toSave = (this.manifestoInput || '').toString().trim();
      if (!toSave) {
        if (Array.isArray(this.manifestoList) && this.manifestoList.length > 0) {
          const idx = Math.floor(Math.random() * this.manifestoList.length);
          toSave = this.manifestoList[idx] && this.manifestoList[idx].name ? this.manifestoList[idx].name : '';
        }
      }

      if (!toSave) { proceedNavigate(); return; }

      // publish to backend, but don't block navigation
      try {
        publishDeclaration([{ workNumber: wn, declaration: toSave }]).then(() => {
          console.log('manifesto published');
        }).catch((err) => { console.error('publishDeclaration failed', err); });
      } catch (e) {}

      // reflect locally so UI shows saved manifesto on next render
      this.manifesto = toSave;
      proceedNavigate();
    },

    /**
     * 跳转至活动说明页面
     */
    navigateToActiveRules() {
      dd.navigateTo({
        url: '/pages/rules/index?track=' + this.userInfo.track + '&role=' + this.userInfo.position
      });
    },

    /**
     * 跳转至指定赛场的排行榜页面
     */
    navigateToTopList(track) {
      // store selected track for non-participant lookup, then navigate to partnerRank
      try {
        dd.setStorage({ key: 'SelectedTrack', data: track });
      } catch (e) {}
      // 不再重置本地表格缓存，直接导航；上游页面可自行处理筛选
      dd.navigateTo({ url: '/pages/partnerRank/index' });
    },

    /**
     * 选择快捷宣言
     */
    selectManifesto(item) { this.manifestoInput = item.name; },

    // 关闭开场弹窗
    closeOpeningPopup() {
      if (this.closingPopupInProgress) return;
      this.closingPopupInProgress = true;
      try {
        const el = typeof document !== 'undefined' ? document.querySelector('.opening-popup') : null;
        if (el) {
          el.classList.remove('closing');
          void el.offsetWidth;
          el.classList.add('closing');
        }
      } catch (e) {}

      this.showOpeningPopup = false;
      this.isOneInPage = true;
      try { dd.setStorage({ key: 'isOneInPage', data: true }); } catch (e) {}
      setTimeout(() => { this.closingPopupInProgress = false; }, 420);
    }
  }
}
</script>

<style scoped> 
@font-face {
  font-family: 'Alimama ShuHeiTi';
  src: 
    url('../../static/fonts/AlimamaShuHeiTi-Bold.woff2') format('woff2'),
    url('../../static/fonts/AlimamaShuHeiTi-Bold.woff') format('woff'),
    url('../../static/fonts/AlimamaShuHeiTi-Bold.ttf') format('truetype'),
    url('../../static/fonts/AlimamaShuHeiTi-Bold.otf') format('opentype');
  font-weight: 700; /* 粗体对应700 */
  font-display: swap; /* 字体加载时使用备用字体渲染 */
}
.container {
  background: url('/static/bg.png') no-repeat center center;
  background-size: cover;
  height: 100vh;
  overflow: hidden;
}
.title-box {
  width: 640rpx;
  height: 208rpx;
  font-family: Alimama ShuHeiTi;
  font-weight: 700;
  font-size: 80rpx;
  line-height: 104rpx;
  text-shadow: 0px 8px 20px rgba(0,0,0,0.3);
  text-align: center;
  font-style: normal;
  text-transform: none;
  background: linear-gradient(23.10958682831623deg, #C5B091 0%, #FFF4DA 60%, #CAB08B 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  margin: 368rpx auto 0;
}
.content-box {
  position: absolute;
  top: 50%;
  left: 0%;
  width: 100%;
  margin-top: 58rpx;
}
.input-box {
  display: flex;
  align-items: center;
  width: 654rpx;
  height: 96rpx;
  background: #fff;
  border-radius: 60rpx;
  padding: 0 40rpx;
  margin: 0 auto;
  overflow: hidden;
  box-sizing: border-box;
}
.input-box input {
  width: 100%;
  height: 40rpx;
  font-size: 28rpx;
  background: #fff;
}
.input-box input::placeholder {
  font-size: 28rpx;
  color: #999999;
}
.manifesto-box {
  padding-top: 42rpx;
}
.manifesto-title {
  font-size: 32rpx;
  color: #FBEDD4;
  margin-left: 48rpx;
  margin-bottom: 42rpx;
}
.manifesto-lines {
  display: block;
}

.marquee-line {
  height: 60rpx;
  overflow: hidden;
  margin-top: 40rpx;
}

.marquee-track {
  display: flex;
  align-items: center;
  gap: 20rpx;
  width: max-content;
  /* animation duration 会通过行内样式覆盖 */
  animation-name: marquee;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  transform: translateX(0);
}

@keyframes marquee {
  from { transform: translateX(0%); }
  to { transform: translateX(-50%); }
}

.manifesto-item {
  display: inline-block;
  height: 64rpx;
  line-height: 64rpx;
  padding: 0 40rpx;
  font-size: 28rpx;
  color: #FBEDD4;
  background: linear-gradient( 90deg, rgba(208,160,118,0.6) 0%, rgba(208,160,118,0) 100%);
  border-radius: 32rpx 40rpx 40rpx 0rpx;
  margin-right: 80rpx;
}
.active-rules-btn {
  width: 136rpx;
  height: 64rpx;
  background: rgba(255,255,255,0.1);
  border-radius: 32rpx 0rpx 0rpx 32rpx;
  position: absolute;
  top: 248rpx;
  right: 0rpx;
  display: flex;
  align-items: center;
  font-size: 24rpx;
  color: #AA9167;
  font-weight: normal;
  z-index: 1000;
  padding-left: 16rpx;
  box-sizing: border-box;
}
.look-box {
  position: fixed;
  bottom: 66rpx;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 96rpx;
}
.look-box-btn {
  width: 654rpx;
  height: 96rpx;
  line-height: 96rpx;
  background: url('/static/btn-bg.png') no-repeat center center;
  background-size: cover;
  border-radius: 60rpx;
  font-size: 32rpx;
  font-weight: 500;
  color: #3D2A2A;
  border: none;
}
.bottom-box {
  width: 100%;
  padding-top: 300rpx;
}
.bottom-box .look-box-btn {
  margin: 0 auto 60rpx;
}
.manifesto-container {
  width: 90%;
  padding-top: 240rpx;
  text-align: center;
  margin: 0 auto;
}
.manifesto-content {
  line-height: 50rpx;
  font-size: 36rpx;
  font-weight: 400;
  color: #FDEBC2;
}
.tips {
  line-height: 50rpx;
  font-size: 36rpx;
  color: #FDEBC2;
  text-align: center;
  margin-bottom: 40rpx;
}

/* 开场弹窗样式与动画 */
.opening-popup-overlay {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(6,6,6,0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  animation: overlayFadeIn 450ms ease forwards;
}
.opening-popup {
  width: 600rpx;
  max-width: 90%;
  border-radius: 30rpx;
  /* background: linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.03)); */
  padding: 40rpx;
  background: #333;
  /* box-shadow: 0 20rpx 60rpx rgba(0,0,0,0.45); */
  display: flex;
  flex-direction: column;
  align-items: center;
  transform-origin: center;
  animation: popupEntrance 900ms cubic-bezier(.2,.9,.2,1) forwards;
  box-shadow: 0 12rpx 30rpx rgba(0,0,0,0.4);
}
.opening-popup.closing { animation: popupExit 420ms cubic-bezier(.4,.0,.2,1) forwards; }
.opening-image {
  width: 560rpx;
  height: 360rpx;
  border-radius: 20rpx;
  /* box-shadow: 0 12rpx 30rpx rgba(0,0,0,0.4); */
  transform-origin: center;
  animation: imageFloat 1800ms ease-in-out infinite;
  margin-bottom: 28rpx;
}
.opening-text {
  font-size: 32rpx;
  color: #FFF7E6;
  text-align: center;
  margin-bottom: 22rpx;
  letter-spacing: 2rpx;
  animation: textGlow 1600ms linear infinite;
}
.opening-close {
  font-size: 26rpx;
  color: #3D2A2A;
  background: linear-gradient(90deg,#FFF4DA,#CAB08B);
  padding: 14rpx 36rpx;
  border-radius: 40rpx;
}

@keyframes overlayFadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes popupEntrance { 0% { transform: scale(0.7) rotateX(25deg) translateY(30rpx); opacity: 0; } 60% { transform: scale(1.05) rotateX(0deg) translateY(0); opacity: 1; } 100% { transform: scale(1) rotateX(0) translateY(0); } }
@keyframes popupExit { to { transform: scale(0.85) translateY(30rpx); opacity: 0; } }
@keyframes imageFloat { 0% { transform: translateY(0) rotate(-1deg); } 50% { transform: translateY(-8rpx) rotate(1deg); } 100% { transform: translateY(0) rotate(-1deg); } }
@keyframes textGlow { 0% { text-shadow: 0 0 0 rgba(255,255,255,0); } 50% { text-shadow: 0 6rpx 22rpx rgba(255,216,140,0.45); } 100% { text-shadow: 0 0 0 rgba(255,255,255,0); } }

/* loading overlay */
.loading-overlay {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(6,6,6,0.6);
  z-index: 3000;
}
.loading-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 30rpx;
  border-radius: 20rpx;
  background: linear-gradient(180deg, rgba(255,255,255,0.03), rgba(255,255,255,0.01));
}
.spinner {
  display: flex;
  gap: 12rpx;
  margin-bottom: 18rpx;
}
.dot {
  width: 22rpx;
  height: 22rpx;
  border-radius: 50%;
  background: linear-gradient(90deg,#E3CBB4,#A5836C);
  animation: pulse 900ms infinite ease-in-out;
}
.dot:nth-child(2) { animation-delay: 120ms; }
.dot:nth-child(3) { animation-delay: 240ms; }
@keyframes pulse {
  0% { transform: scale(0.7); opacity: 0.5; }
  50% { transform: scale(1.05); opacity: 1; }
  100% { transform: scale(0.7); opacity: 0.5; }
}
.loading-text {
  color: #FDEBC2;
  font-size: 28rpx;
}
.loading-note {
  color: #FFDFAF;
  font-size: 26rpx;
  margin-bottom: 12rpx;
  text-align: center;
}

/* 添加非参赛人员按钮网格样式 */
.grid-container {
  display: flex;
  flex-wrap: wrap;
  gap: 50rpx;
  width: 654rpx;
  margin: 100rpx auto 0;
  padding-top: 40rpx;
  justify-content: center;
  box-sizing: border-box;
}
.grid-btn {
  flex: 0 0 300rpx;
  height: 96rpx;
  line-height:96rpx;
  text-align: center;
  border-radius: 50rpx;
  background: url('/static/btn-bg.png') no-repeat center center;
  background-size: 100% 100%;
  color: #3D2A2A;
  font-size: 28rpx;
  font-weight: 500;
  border: none;
  box-shadow: 0 6rpx 18rpx rgba(12,93,166,0.12);
}
.grid-btn.full {
  flex: 0 0 100%;
  width: 654rpx;
}
.non-participant-area {
  padding-top: 40rpx;
}
</style>